Skip to content

feat: fix AI session auto-renaming title extraction / 修复会话自动重命名标题提取#941

Open
WenhuaXia wants to merge 4 commits into
siteboon:mainfrom
WenhuaXia:feat/auto-rename-session-fix
Open

feat: fix AI session auto-renaming title extraction / 修复会话自动重命名标题提取#941
WenhuaXia wants to merge 4 commits into
siteboon:mainfrom
WenhuaXia:feat/auto-rename-session-fix

Conversation

@WenhuaXia

@WenhuaXia WenhuaXia commented Jun 30, 2026

Copy link
Copy Markdown

Problem / 问题

When the AI model quotes the user's message in its thinking block (e.g. - **User's message:** "..."), the session title extraction mistakenly used the user's own prompt as the session name.

AI 模型在 thinking 块中引用用户消息时,会话重命名逻辑将用户原话误当作标题。

Solution / 修复

  • isPromptMatch() strips markdown prefixes (markdown bold, wrapper quotes/backticks) before comparison
  • Added extractTitleFromThinking() for reasoning models (Qwen etc.) that produce thinking instead of text blocks
  • Added truncateToTitle() fallback with Chinese conversational prefix stripping
  • Lowered overlap threshold from 0.7 to 0.5 for prompt matching
  • Guarded text block path against prompt-as-title

Changed Files

  • server/modules/providers/list/claude/claude-session-synchronizer.provider.ts

Summary by CodeRabbit

  • New Features

    • Improved session title auto-generation with smarter reuse of existing titles and AI-backed title creation, plus stronger fallbacks.
    • Enhanced Claude streaming support with partial content updates for more responsive output.
  • Bug Fixes

    • Prevented session “title/summary downgrade” by preserving existing summary when incoming values are empty or default placeholders.
    • Improved handling of task-related prompt context during message normalization.
    • Reduced noisy console logging during streaming and session reconnect events.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Anthropic-backed session title generation and JSONL title parsing, updates Claude SDK streaming to capture Task subagent prompts, and preserves existing project summaries when incoming values are placeholders.

Changes

AI Session Title and Streaming Updates

Layer / File(s) Summary
Anthropic title generation and parsing
server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
resolveAnthropicConfig() resolves Anthropic credentials from env, settings, and credentials files; generateAiTitle() calls /v1/messages and falls back through thinking extraction and truncation; extractTitleFromThinking(), isPromptMatch(), and truncateToTitle() post-process title candidates.
JSONL title sources and reuse logic
server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
extractLastPrompt() reads the latest last-prompt entry from JSONL; extractSessionAiTitleFromEnd() returns { title, kind } for custom-title and ai-title records; processSessionFile() falls back through nameMap, JSONL extraction, and AI generation while avoiding placeholder reuse.
Task prompt capture in Claude SDK
server/claude-sdk.js
extractSubagentPrompt() parses Task tool_use inputs from object and JSON string forms; queryClaudeSDK() enables partial messages, collects Task prompts in a per-query Set, passes that context into normalizeMessage(), and removes startup, abort, and reconnect console logs.
Existing session summary guard
src/hooks/useProjectsState.ts
upsertSessionIntoProject() preserves an existing non-empty summary when the incoming summary or name is missing or equals the Untitled Claude Session placeholder.

Possibly related PRs

  • siteboon/claudecodeui#208: Extends the same server/claude-sdk.js streaming path that this PR updates with Task subagent prompt capture.

Suggested reviewers: blackmammoth, viper151

Poem

🐇 I hopped through titles, prompt by prompt,
And caught each Task tool in a prompty romp.
With streaming streams and summaries kept neat,
No placeholder fog could trick my treat.
Hop hop—now session names feel sweet!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: fixing AI session auto-renaming title extraction.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/claude-sdk.js`:
- Around line 59-60: The JSON parsing guard in claude-sdk.js is too loose
because JSON.parse('null') still passes the object check and then reading
parsed.prompt can throw. Update the parsing path around the parsed variable to
explicitly reject null before accessing prompt, then keep the existing prompt
extraction logic so the SDK stream safely returns null instead of crashing.
- Around line 754-759: `sessionsService.normalizeMessage` is being called with
`streamingSubagentPrompts`, but the service and Claude provider signatures still
only accept three arguments, so the prompt filter data is dropped. Update the
`normalizeMessage` method in the sessions service, the provider interface, and
the Claude provider implementation to accept the optional fourth parameter and
forward it through to the normalization logic. Make sure the
`streamingSubagentPrompts` Set is passed all the way through so Task prompt
filtering can run during normalization.

In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Around line 393-398: The auto-title logging in the session synchronizer is
exposing user prompt text and generated titles, so update the
`claude-session-synchronizer.provider.ts` flow inside the `if (!sessionName)`
block to stop logging sensitive contents. Keep the `console.info` messages in
place if needed, but remove the `prompt` and `title` payloads from the logs in
the `extractLastPrompt` and `generateAiTitle` path, and only log non-sensitive
context such as the session ID.
- Around line 289-296: The prompt-echo check in
claude-session-synchronizer.provider.ts is too aggressive because p.includes(c)
treats a valid title as invalid when it appears inside the prompt. Update the
matching logic in the title-validation path to only reject obvious prompt echoes
or near-duplicates, and avoid using a plain substring containment test against
the full prompt; keep the existing heuristics in the surrounding comparison
function but make the decision in this block rely on stronger signals than
simple inclusion.
- Around line 232-263: The early decision extraction paths in the title parsing
logic can still return prompt-echoed text because they bypass the prompt guard
used later in the same method. Update the candidate handling in the
`claude-session-synchronizer.provider.ts` title extraction flow so every matched
value from the decision and backtick patterns is checked with `isPromptMatch`
against `userPrompt` before returning. Keep the existing fallback behavior in
the relevant parsing routine, but make the guard apply consistently across all
candidate sources, including the initial `decisionPatterns` and
`backtickPatterns` branches.
- Around line 363-371: The skip logic in the Claude session synchronizer is
treating any custom session name longer than 60 characters as eligible for
regeneration, which can overwrite valid user-defined titles. Update the guard in
the session-name handling flow around the existingSessionName check so it
preserves custom names up to the full limit supported by normalizeSessionName
(60 should not be the cutoff), and keep the prompt-derived-name detection using
extractLastPrompt intact. Ensure the decision in ClaudeSessionSynchronizer
reflects “skip unless the name is prompt-derived,” not “skip only when the name
is short.”
- Around line 458-463: The custom-title handling in
claude-session-synchronizer.provider.ts should stop searching once the latest
title is the placeholder, instead of continuing backward and potentially
returning an older stale title. Update the title-scanning logic around the
custom-title branch in the session sync flow so that when claudeRenamedTitle is
"Untitled Claude Session" it is treated as no title and the search terminates
there, allowing AI generation to proceed rather than falling back to earlier
titles.
- Around line 119-133: The auth handling in resolveAnthropicConfig is collapsing
ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN into a single key, which loses
whether the request should use x-api-key or Authorization: Bearer. Update the
config flow in claude-session-synchronizer.provider.ts so it preserves the
credential kind alongside the value, and make the Anthropic request builder
choose the correct header based on that kind. Keep the env and settings.json
reading logic in place, but ensure the returned config from
resolveAnthropicConfig and the caller that sends the Messages request both use
the credential type explicitly.

In `@src/hooks/useProjectsState.ts`:
- Around line 260-267: The downgrade path in useProjectsState currently restores
only summary when normalizedSession has a degraded title, but name can still be
overwritten by the incoming “Untitled Claude Session”. Update the
isDegradedSummary branch so it preserves both session.summary and session.name
from the existing session before/after spreading normalizedSession, using the
existing session and updated object logic in this hook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4e04fa80-a9ec-41a7-8ee3-8f2994fe0139

📥 Commits

Reviewing files that changed from the base of the PR and between 2ebe64f and 2e1a3bc.

📒 Files selected for processing (3)
  • server/claude-sdk.js
  • server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
  • src/hooks/useProjectsState.ts

Comment thread server/claude-sdk.js Outdated
Comment thread server/claude-sdk.js
Comment on lines +119 to +133
if (process.env.ANTHROPIC_API_KEY?.trim()) key = process.env.ANTHROPIC_API_KEY.trim();
if (process.env.ANTHROPIC_AUTH_TOKEN?.trim()) key = process.env.ANTHROPIC_AUTH_TOKEN.trim();
if (process.env.ANTHROPIC_BASE_URL?.trim()) baseUrl = process.env.ANTHROPIC_BASE_URL.trim();

// Read from ~/.claude/settings.json env block
try {
const settingsPath = path.join(this.claudeHome, 'settings.json');
const content = await readFile(settingsPath, 'utf8');
const settings: any = JSON.parse(content);
const env = settings?.env;
if (typeof env === 'object' && env) {
if (typeof env.ANTHROPIC_API_KEY === 'string' && env.ANTHROPIC_API_KEY.trim()) key = env.ANTHROPIC_API_KEY.trim();
if (typeof env.ANTHROPIC_AUTH_TOKEN === 'string' && env.ANTHROPIC_AUTH_TOKEN.trim()) key = env.ANTHROPIC_AUTH_TOKEN.trim();
if (typeof env.ANTHROPIC_BASE_URL === 'string' && env.ANTHROPIC_BASE_URL.trim()) baseUrl = env.ANTHROPIC_BASE_URL.trim();
if (typeof env.ANTHROPIC_DEFAULT_HAIKU_MODEL === 'string' && env.ANTHROPIC_DEFAULT_HAIKU_MODEL.trim()) model = env.ANTHROPIC_DEFAULT_HAIKU_MODEL.trim();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- outline ---'
ast-grep outline server/modules/providers/list/claude/claude-session-synchronizer.provider.ts --view expanded || true

echo '--- relevant lines ---'
nl -ba server/modules/providers/list/claude/claude-session-synchronizer.provider.ts | sed -n '100,190p'

echo '--- search x-api-key / ANTHROPIC_AUTH_TOKEN ---'
rg -n "x-api-key|ANTHROPIC_AUTH_TOKEN|ANTHROPIC_API_KEY|Authorization: \`Bearer|authHeader" server/modules/providers server/modules -g'*.ts' -g'*.js' || true

Repository: siteboon/claudecodeui

Length of output: 1360


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- relevant lines 113-190 ---'
sed -n '113,190p' server/modules/providers/list/claude/claude-session-synchronizer.provider.ts

echo '--- relevant lines 190-250 ---'
sed -n '190,250p' server/modules/providers/list/claude/claude-session-synchronizer.provider.ts

echo '--- other Anthropic-related usages ---'
rg -n "resolveAnthropicConfig|generateAiTitle|x-api-key|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|Authorization: \`Bearer" server -g'*.ts' -g'*.js' || true

Repository: siteboon/claudecodeui

Length of output: 9144


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- claude-auth.provider.ts relevant lines ---'
sed -n '1,160p' server/modules/providers/list/claude/claude-auth.provider.ts

echo '--- opencode-auth.provider.ts relevant lines ---'
sed -n '1,120p' server/modules/providers/list/opencode/opencode-auth.provider.ts

echo '--- search credential handling in claude files ---'
rg -n "ANTHROPIC_AUTH_TOKEN|ANTHROPIC_API_KEY|x-api-key|Authorization: \`Bearer|Bearer \${.*key" server/modules/providers/list/claude -g'*.ts' || true

Repository: siteboon/claudecodeui

Length of output: 8638


🌐 Web query:

Anthropic Messages API authentication headers x-api-key Authorization Bearer official docs ANTHROPIC_API_KEY ANTHROPIC_AUTH_TOKEN

💡 Result:

The Anthropic Messages API supports two primary authentication methods: standard API keys and Workload Identity Federation (WIF) [1][2]. Authentication Headers: - x-api-key: Used for static API keys (typically starting with sk-ant-api...) [1]. This header is the standard way to provide your API key for authentication [2][3]. - Authorization: Bearer : Used for short-lived access tokens obtained through Workload Identity Federation [1][2]. Requirements: All API requests must include one of the two authentication headers listed above [2]. Additionally, all requests must include the following mandatory headers: - anthropic-version: Specifies the API version (e.g., 2023-06-01) [2][3]. - content-type: Must be set to application/json [2][3]. SDK Environment Variables: - ANTHROPIC_API_KEY: The official SDKs (Python, TypeScript, etc.) automatically detect and use this environment variable to populate the x-api-key header [1][2][4]. - ANTHROPIC_AUTH_TOKEN: Used in some SDK implementations (or custom integrations) to populate the Authorization: Bearer header [5][6]. If you are using the official Anthropic SDKs, they manage these headers automatically, so you generally do not need to construct them manually [1][2]. When making direct HTTP requests (e.g., via curl), ensure you provide the x-api-key header along with the required version and content-type headers [3]. Note that while some OAuth-related tokens may have historically supported Bearer authentication, current guidance emphasizes the x-api-key header for standard API key-based access [1][7].

Citations:


Preserve Anthropic auth type in the request. Anthropic Messages expects x-api-key for ANTHROPIC_API_KEY and Authorization: Bearer for ANTHROPIC_AUTH_TOKEN/OAuth, so resolveAnthropicConfig should carry the credential kind instead of collapsing both into key; otherwise API-key-only installs will 401 and always fall back to truncation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
around lines 119 - 133, The auth handling in resolveAnthropicConfig is
collapsing ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN into a single key, which
loses whether the request should use x-api-key or Authorization: Bearer. Update
the config flow in claude-session-synchronizer.provider.ts so it preserves the
credential kind alongside the value, and make the Anthropic request builder
choose the correct header based on that kind. Keep the env and settings.json
reading logic in place, but ensure the returned config from
resolveAnthropicConfig and the caller that sends the Messages request both use
the credential type explicitly.

Comment thread server/modules/providers/list/claude/claude-session-synchronizer.provider.ts Outdated
Comment thread server/modules/providers/list/claude/claude-session-synchronizer.provider.ts Outdated
Comment thread server/modules/providers/list/claude/claude-session-synchronizer.provider.ts Outdated
Comment thread src/hooks/useProjectsState.ts
When the AI model quotes the user's message in its thinking block
(e.g. '- **User's message:** ...'), the title extraction mistakenly
used the user's own prompt as the session name.

Changes:
- Add isPromptMatch() to strip markdown prefixes and detect prompt echoes
- Add extractTitleFromThinking() for reasoning models (Qwen etc.)
- Add truncateToTitle() fallback with Chinese prefix stripping
- Lower overlap threshold from 0.7 to 0.5 for prompt matching
- Guard text block path against prompt-as-title

Fixes: siteboon#926, siteboon#935
Prevent backend 'Untitled Claude Session' or empty titles from overwriting
the user-set frontend title in the sidebar.
@WenhuaXia WenhuaXia force-pushed the feat/auto-rename-session-fix branch from 2e1a3bc to c3bf430 Compare June 30, 2026 16:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Line 116: The fallback model in claudeSessionSynchronizer is using an outdated
Claude Haiku ID, so update the default in the model selection logic to a current
Claude Haiku 4.5 value. In claude-session-synchronizer.provider.ts, adjust the
let model initialization to use the documented alias or pinned ID
(claude-haiku-4-5 or claude-haiku-4-5-20251001) so /v1/messages resolves to a
valid model.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0ac08c64-173f-4e8d-8662-594e8f09c8a9

📥 Commits

Reviewing files that changed from the base of the PR and between 2e1a3bc and c3bf430.

📒 Files selected for processing (3)
  • server/claude-sdk.js
  • server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
  • src/hooks/useProjectsState.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/hooks/useProjectsState.ts
  • server/claude-sdk.js

private async resolveAnthropicConfig(): Promise<{ key: string; baseUrl: string; model: string } | null> {
let key: string | null = null;
let baseUrl = 'https://api.anthropic.com';
let model = 'claude-haiku-4-20250915';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the provider around the default model and its callers/usages.
grep -nR --line-number --context=3 "claude-haiku-4" server/modules/providers/list/claude || true

echo
echo "=== file slice ==="
sed -n '90,150p' server/modules/providers/list/claude/claude-session-synchronizer.provider.ts

echo
echo "=== search for other Claude model defaults ==="
grep -R --line-number --context=2 "claude-haiku-4\|claude-sonnet\|claude-opus" server | head -200 || true

Repository: siteboon/claudecodeui

Length of output: 18683


🌐 Web query:

Anthropic Claude model IDs Haiku 4.5 claude-haiku-4-5-20251001 alias documentation current

💡 Result:

For Claude Haiku 4.5, the specific model ID and alias are as follows: - Claude API ID: claude-haiku-4-5-20251001 [1][2] - Claude API Alias: claude-haiku-4-5 [1][2] In the context of the Claude API, Claude Haiku 4.5 uses a dated model ID (claude-haiku-4-5-20251001) to represent a fixed, pinned snapshot of the model [3][1]. The alias (claude-haiku-4-5) acts as a convenience pointer that resolves to this specific dated version [1]. For other platforms, the identifiers differ to accommodate their specific naming requirements: - Amazon Bedrock: anthropic.claude-haiku-4-5-20251001-v1:0 [4][2] - Google Cloud Vertex AI: claude-haiku-4-5@20251001 [2] Anthropic documentation clarifies that for models released prior to the Claude 4.6 generation, such as Haiku 4.5, aliases serve as pointers to dated snapshots [3][1]. Starting with the 4.6 generation, model IDs transitioned to a dateless format which serves as the canonical, pinned snapshot ID itself [3].

Citations:


Use a current Claude Haiku default model. claude-haiku-4-20250915 is not a current Claude Haiku 4.5 ID; the documented alias is claude-haiku-4-5 and the pinned ID is claude-haiku-4-5-20251001. If this fallback is used, /v1/messages will target an unknown model.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
at line 116, The fallback model in claudeSessionSynchronizer is using an
outdated Claude Haiku ID, so update the default in the model selection logic to
a current Claude Haiku 4.5 value. In claude-session-synchronizer.provider.ts,
adjust the let model initialization to use the documented alias or pinned ID
(claude-haiku-4-5 or claude-haiku-4-5-20251001) so /v1/messages resolves to a
valid model.

WenhuaXia added 2 commits July 1, 2026 12:37
- Guard JSON null before reading prompt in claude-sdk.js
- Apply prompt-echo guard to all thinking candidates (decision patterns)
- Don't reject valid titles just because they're contained in prompt (near-full overlap check)
- Preserve real custom names longer than 60 characters
- Remove prompt/title contents from logs (console.debug instead of console.info)
- Stop scanning after latest placeholder title (custom-title logic)
- Preserve name as well as summary on title downgrade

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
server/modules/providers/list/claude/claude-session-synchronizer.provider.ts (2)

319-319: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix multi-character Chinese prefix stripping.

[一下]? and [一下一眼]? are character classes, so 查一下配置 leaves 下配置. Use grouped alternatives for multi-character phrases.

Proposed fix
-    title = title.replace(/^(\s*?(你帮[我忙]?[下看查]+|你看[下查]+|你帮[下看查]+|你给我|你(帮)?[下看查]+|请帮[我忙]?[下看查]+|请[下看查]+|帮[我忙]?[下看查]+|查[一下]?|调查[一下]?|看[一下一眼]?|我先了解下?|我先了解[下查]+|你先[了解下查]+)[\s::]*)/, '');
+    title = title.replace(/^(\s*?(你帮[我忙]?[下看查]+|你看[下查]+|你帮[下看查]+|你给我|你(帮)?[下看查]+|请帮[我忙]?[下看查]+|请[下看查]+|帮[我忙]?[下看查]+|查(?:一下|下)?|调查(?:一下|下)?|看(?:一下|下|一眼)?|我先了解下?|我先了解[下查]+|你先[了解下查]+)[\s::]*)/, '');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
at line 319, The prefix-stripping regex in
claude-session-synchronizer.provider.ts is treating multi-character Chinese
phrases as character classes, so inputs like 查一下配置 can still leave a trailing
fragment. Update the title normalization regex used in the title replacement
logic to use grouped alternatives for multi-character phrases in the same
pattern, and verify the matching around the title = title.replace(...) call
still removes all intended request prefixes without leaving partial characters.

281-283: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize plain prompt labels and smart quotes.

The current stripping only handles bold markdown labels, so candidates like User's first message: ... or “<prompt>” can pass as non-matches and be used as titles.

Proposed fix
-    c = c.replace(/^[-*]\s*\*\*[^*]*\*\*\s*:?[""]?\s*/, '');
-    c = c.replace(/^[-*]\s*["`]\s*/, '');
-    c = c.replace(/["`\s]+$/, '').trim();
+    c = c.replace(/^[-*]\s*/, '');
+    c = c.replace(/^\*\*(?:user(?:'s)?(?: first)? message|user|prompt)\s*:?\*\*\s*:?\s*/i, '');
+    c = c.replace(/^(?:user(?:'s)?(?: first)? message|user|prompt)\s*:?\s*/i, '');
+    c = c.replace(/^[`"'“”‘’]\s*/, '');
+    c = c.replace(/[`"'“”‘’\s]+$/, '').trim();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
around lines 281 - 283, Update the candidate normalization in
claude-session-synchronizer.provider.ts where the label cleanup is done so it
also strips plain prompt labels like User's first message: and removes smart
quotes around candidates, not just bold markdown. Adjust the existing replace
logic in the candidate normalization block so the matching used for title
selection in the synchronizer treats those wrapped or labeled strings as
non-titles consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Around line 376-381: The title fallback check in
claude-session-synchronizer.provider.ts only treats prompt-prefix names as
generated when trimmedExistingName.length is at least 60, so shorter values
produced by truncateToTitle() can be mistaken for custom names. Update the guard
around the exact-name/prefix comparison to also detect fallback titles below 60
chars using the same trimming logic in this block, so prompt-derived titles
still trigger AI regeneration when they exactly match or closely prefix
trimmedPrompt.

---

Outside diff comments:
In
`@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`:
- Line 319: The prefix-stripping regex in
claude-session-synchronizer.provider.ts is treating multi-character Chinese
phrases as character classes, so inputs like 查一下配置 can still leave a trailing
fragment. Update the title normalization regex used in the title replacement
logic to use grouped alternatives for multi-character phrases in the same
pattern, and verify the matching around the title = title.replace(...) call
still removes all intended request prefixes without leaving partial characters.
- Around line 281-283: Update the candidate normalization in
claude-session-synchronizer.provider.ts where the label cleanup is done so it
also strips plain prompt labels like User's first message: and removes smart
quotes around candidates, not just bold markdown. Adjust the existing replace
logic in the candidate normalization block so the matching used for title
selection in the synchronizer treats those wrapped or labeled strings as
non-titles consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ef77a1cb-c741-4013-89b3-17908da3819a

📥 Commits

Reviewing files that changed from the base of the PR and between c3bf430 and 55d2491.

📒 Files selected for processing (4)
  • .gitignore
  • server/claude-sdk.js
  • server/modules/providers/list/claude/claude-session-synchronizer.provider.ts
  • src/hooks/useProjectsState.ts
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/hooks/useProjectsState.ts
  • server/claude-sdk.js

Comment on lines +376 to +381
if (
trimmedPrompt
&& (
trimmedExistingName === trimmedPrompt
|| (trimmedExistingName.length >= 60 && trimmedPrompt.startsWith(trimmedExistingName))
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Detect exact fallback titles below 60 chars.

truncateToTitle() can cut at whitespace/sentence boundaries before 60 chars, but this guard only regenerates prompt-prefix names when trimmedExistingName.length >= 60. Those shorter fallback titles get treated as custom names and skip AI regeneration.

Proposed fix
+      const promptFallbackTitle = trimmedPrompt ? this.truncateToTitle(trimmedPrompt).trim() : undefined;
       if (
         trimmedPrompt
         && (
           trimmedExistingName === trimmedPrompt
-          || (trimmedExistingName.length >= 60 && trimmedPrompt.startsWith(trimmedExistingName))
+          || trimmedExistingName === promptFallbackTitle
         )
       ) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (
trimmedPrompt
&& (
trimmedExistingName === trimmedPrompt
|| (trimmedExistingName.length >= 60 && trimmedPrompt.startsWith(trimmedExistingName))
)
const promptFallbackTitle = trimmedPrompt ? this.truncateToTitle(trimmedPrompt).trim() : undefined;
if (
trimmedPrompt
&& (
trimmedExistingName === trimmedPrompt
|| trimmedExistingName === promptFallbackTitle
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/providers/list/claude/claude-session-synchronizer.provider.ts`
around lines 376 - 381, The title fallback check in
claude-session-synchronizer.provider.ts only treats prompt-prefix names as
generated when trimmedExistingName.length is at least 60, so shorter values
produced by truncateToTitle() can be mistaken for custom names. Update the guard
around the exact-name/prefix comparison to also detect fallback titles below 60
chars using the same trimming logic in this block, so prompt-derived titles
still trigger AI regeneration when they exactly match or closely prefix
trimmedPrompt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant